package com.jf.identity.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.jf.identity.util.Params;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

/**
 * 处理data数据,封装成controller入参
 *
 * @author FCG
 */
@Component
public class JsonDataHandler implements ParamHandler<HttpServletRequest, Object> {
    private Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public HttpServletRequest handle(Object param, HttpServletRequest request, HttpServletResponse response) {
        Object data = Params.isBlank(param, "data");
        //传递给controller的请求参数
        JSONObject handledBody = null;
        if (data instanceof JSONObject) {
            handledBody = (JSONObject) data;
        } else if (data instanceof String) {
            try {
                handledBody = JSON.parseObject((String) data);
            } catch (JSONException ex) {
                logger.info("data数据非标准json格式,{}", ex.getMessage());
                throw new IllegalArgumentException("data数据非标准json格式", ex);
            }
        }
        if (handledBody == null) {
            throw new IllegalArgumentException("无法解析data数据");
        }
        return new HttpPostBodyRequestWrapper(request, handledBody);
    }


    /**
     * 封装了json数据的httpRequest
     */
    private static class HttpPostBodyRequestWrapper extends HttpServletRequestWrapper {
        /**
         * http请求参数
         */
        private JSONObject body;

        public HttpPostBodyRequestWrapper(HttpServletRequest request, JSONObject body) {
            super(request);
            Objects.requireNonNull(body);
            this.body = body;
        }

        @Override
        public ServletInputStream getInputStream() {
            byte[] bytes = JSON.toJSONBytes(body);
            return new HttpPostBodyInputStream(
                    new ByteArrayInputStream(bytes)
            );
        }

        @Override
        public String getContentType() {
            String t = super.getContentType();
            return "application/json";
        }

        @Override
        public String getHeader(String name) {
            String t = super.getHeader(name);
            if ("Content-Type".equalsIgnoreCase(name)) {
                return "application/json";
            }
            return t;
        }

        @Override
        public Enumeration<String> getHeaders(String name) {
            Enumeration<String> t = super.getHeaders(name);
            if ("Content-Type".equalsIgnoreCase(name)) {
                List<String> list = new ArrayList<>();
                list.add("application/json");
                return Collections.enumeration(list);
            }
            return t;
        }
//        @Override
//        public Map<String, String[]> getParameterMap() {
//            Map<String, String[]> t = super.getParameterMap();
//            int size = body.size();
//            Map<String, String[]> map = new HashMap<>(size);
//            Map<String, Object> innerMap = body.getInnerMap();
//            for (Map.Entry<String, Object> entry : innerMap.entrySet()) {
//                String key = entry.getKey();
//                Object value = entry.getValue();
//                if (value instanceof String) {
//                    map.put(key, new String[]{String.valueOf(value)});
//                    continue;
//                }
//                if (value.getClass().isArray() || value instanceof Collection) {
//                    Object[] arr = body.getJSONArray(key).toArray();
//                    String[] values = new String[arr.length];
//                    for (int i = 0; i < arr.length; i++) {
//                        values[i] = String.valueOf(arr[i]);
//                    }
//                    map.put(key, values);
//                }
//            }
//            return t;
//        }
//
//        @Override
//        public String getParameter(String name) {
//            String t = super.getParameter(name);
//            String value = String.valueOf(body.getInnerMap().get(name));
//            return t;
//        }
//
//        @Override
//        public Enumeration<String> getParameterNames() {
//            Enumeration<String> t = super.getParameterNames();
//            Set<String> names = body.getInnerMap().keySet();
////            return Collections.enumeration(names);
//            return t;
//        }
//
//        @Override
//        public String[] getParameterValues(String name) {
//            String[] t = super.getParameterValues(name);
//            Object value = body.getInnerMap().get(name);
//            if (value instanceof String) {
//                return new String[]{String.valueOf(value)};
//            }
//            if (value.getClass().isArray() || value instanceof Collection) {
//                Object[] arr = body.getJSONArray(name).toArray();
//                String[] values = new String[arr.length];
//                for (int i = 0; i < arr.length; i++) {
//                    values[i] = String.valueOf(arr[i]);
//                }
//                return values;
//            }
////            return new String[]{String.valueOf(value)};
//            return t;
//        }
    }

    /**
     * 从json格式的请求数据中获取输入流
     */
    private static class HttpPostBodyInputStream extends ServletInputStream {

        private InputStream sourceStream;
        private boolean finished = false;

        public HttpPostBodyInputStream(InputStream sourceStream) {
            Objects.requireNonNull(sourceStream);
            this.sourceStream = sourceStream;
        }

        @Override
        public boolean isFinished() {
            return this.finished;
        }

        @Override
        public boolean isReady() {
            return true;
        }

        @Override
        public void setReadListener(ReadListener listener) {
            // do nothing
        }

        @Override
        public int read() throws IOException {
            int data = this.sourceStream.read();
            if (data == -1) {
                this.finished = true;
            }
            return data;
        }
    }
}
